﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using PJ.Business;
using Microsoft.Practices.Composite.Events;

namespace PJ.Presentation
{
    public abstract class BusinessObjectViewModel : BaseViewModel, IBusinessObjectModel
    {
        #region Constructor

        protected BusinessObjectViewModel(IView view, IEventAggregator aggregator, IBusinessObjectService service)
            : base(view, aggregator)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            _Service = service;
            EventAggregator.GetEvent<ApplicationCloseEvent>().Subscribe(OnApplicationClose);
        }

        protected BusinessObjectViewModel(string globalId, IBusinessObjectService service)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            if (globalId == null || globalId == "")
                throw new ArgumentNullException("globalId");
            _Service = service;
            SetValues(globalId);
        }

        protected BusinessObjectViewModel(IBusinessObject obj, IBusinessObjectService service)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            if (obj == null)
                throw new ArgumentNullException("obj");
            _Service = service;
            SetValues(obj, false);
        }

        protected BusinessObjectViewModel()
        {
            _Service = null;
        }

        #endregion

        #region Interface implementation

        public IBusinessObjectService Service
        {
            get
            {
                if (_Service == null)
                    throw new Exception("Service is not initialized");
                return _Service;
            }
            set
            {
                if (_Service != value)
                {
                    if (_Service != null)
                    {
                        if (value != null)
                            throw new Exception("Service is already initialized");
                        _Service.Dispose();
                    }
                    _Service = value;
                }
            }
        }


        /// <summary>
        /// GetValues. Sets the businness object properties using the model property values
        /// </summary>
        /// <param name="businessObject">business object to update</param>
        public virtual IBusinessObject GetValues()
        {
            return BusinessObject;
        }
        /// <summary>
        /// SetValues. Sets the model properties using the businessobject property values
        /// </summary>
        /// <param name="businessObject"></param>
        public virtual void SetValues(IBusinessObject businessObject, bool saveBefore)
        {
            if (saveBefore)
                Persist();
            BusinessObject = businessObject;
            if (_BusinessObject == null)
                GlobalId = null;
            else
                GlobalId = BusinessObject.GlobalId;
        }

        #endregion

        /// <summary>
        /// SetValues. Sets the model properties using the businessobject property values
        /// </summary>
        /// <param name="globalId">Source object globalId</param>
        public virtual void SetValues(string globalId)
        {
            if (globalId == null || globalId == "")
                SetValues((IBusinessObject)null, true);
            else
                SetValues(Service.GetData(globalId, PJ.Data.GetDataMode.UseCache), true);
        }

        public string GlobalId
        {
            get
            {
                return (string)ThreadUnsafeGetValue(GlobalIdProperty);
            }
            set
            {
                if (!StringEqual(GlobalId, value))
                    ThreadUnsafeSetValue(GlobalIdProperty, value);
            }
        }

        public static readonly DependencyProperty GlobalIdProperty =
            DependencyProperty.Register("GlobalId", typeof(string), typeof(BusinessObjectViewModel), new UIPropertyMetadata(""));


        public virtual void Persist()
        {
            if (ValuesChanged())
            {
                IBusinessObject persisted = Service.PersistAndGet(GetValues());
                if (persisted.GlobalId != GlobalId)
                    if (GlobalId != null && GlobalId != "")
                        throw new Exception("Object persist error");
                ThreadUnsafeSetValue(GlobalIdProperty, persisted.GlobalId); // override values changed check
                SetValues(persisted, false);
            }
        }

        public override void Dispose()
        {
            Persist();
            Service = null;
        }

        #region Protected

        protected virtual bool ValuesChanged()
        {
            return false;
        }

        protected virtual void OnApplicationClose(bool cancel)
        {
            Dispose();
        }
        protected void OnSelectionChange(BusinessEventArgs args)
        {
            string globalId;
            if (args == null)
                globalId = null;
            else
                if (args.GlobalId == null || args.GlobalId == "")
                    globalId = null;
                else
                    globalId = args.GlobalId;
            if (GlobalId != globalId)
                SetValues(globalId);
        }
        protected bool StringEqual(string str1, string str2)
        {
            if (str1 == str2)
                return true;

            if (str1 == null)
                if (str2 == null || str2.Length == 0)
                    return true;
                else
                    return false;
            if (str2 == null || str2.Length == 0)
                return false;
            return str1.Equals(str2);
        }

        protected bool IsStringNull(string str)
        {
            if (str == null || str.Length == 0)
                return true;
            else
                return false;
        }

        protected IBusinessObject BusinessObject
        {
            get
            {
                if (_BusinessObject == null)
                    _BusinessObject = Service.CreateNewItem();
                return _BusinessObject;
            }
            set { _BusinessObject = value; }
        }

        protected bool IsBusinessObjectNull
        {
            get
            {
                return _BusinessObject == null;
            }
        }

        #endregion

        #region Private

        private IBusinessObject _BusinessObject;

        #endregion
        #region Field



        protected IBusinessObjectService _Service;


        #endregion
    }
}
